﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Runtime.CompilerServices;


//using NameValueCollection = List<KeyValuePair<string, string>>;
//using HashTable = System.Collections.Generic.Dictionary<object, object>;

namespace MyMailWp8.Protocol
{
    public enum CMPopTaskType
    {
        CMPopRecvMailTaskType = 1,              //不要用0，C#中0有特殊意义，可以直接转换成enum类型
        CMPopRecvAttachmentTaskType = 10,
        CMPopEMSTaskType = 20
    };

    public delegate void CMPopStateEventHandler(int nState);


    /*
     * yang:20130614
     * 向Task方向修改
     * 实现层间业务分离
     * 
     * 
     */
    /// <summary>
    /// POP3协议
    /// </summary>
    public class CMPop
    {
        private CMPopState _nPopState;
        private CMPopTaskType _nCMPopTaskType; // 1-receive mail, 10-receive attachment
        private CMPopBase _cmPopCommand;

        private AsyncSocketClient _sockClient;
        private List<CMPopAttDownloadInfo> _attDownloadList = null;

        public event TransportEventHandler TransportEvent;

        public event AttachmentDownloadProcessEventHandler AttachmentDownloadProcessEvent;

        private System.Object lockObject = new System.Object();


        #region Members

        public readonly string server = "";
        public readonly int port = 0;

        #endregion

        public CMPop()
        {
            initPopAccountSocket();
        }

        private void initPopAccountSocket()
        {
            _nPopState = CMPopState.CMPOP_Init;
            _sockClient = new AsyncSocketClient(server, port);//MIG
            _sockClient.ResponseReceived += new ResponseReceivedHandler(CMPopCallBack);
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public void Dispose()
        {
            try
            {
                TransportEvent = null;
                AttachmentDownloadProcessEvent = null;
                if (_cmPopCommand != null)
                    _cmPopCommand.resetEvent();
                CMPopChangeState((int)CMPopState.CMPOP_Quit);
                _sockClient.DisConnectToSever();
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public void StartCMPopRecv()
        {
            if (_nPopState != CMPopState.CMPOP_Init)
                return;

            startTask(CMPopTaskType.CMPopRecvMailTaskType);
        }


        public void StartCMPopFetchAttachment()
        {
            if (_nPopState != CMPopState.CMPOP_Init)
                return;

            startTask(CMPopTaskType.CMPopRecvAttachmentTaskType);
        }

        private void startTask(CMPopTaskType taskType)
        {
            _nCMPopTaskType = taskType;
            try
            {
                _sockClient.connectToSever();
            }
            catch (PESocketException ex)
            {
                callErrorTransportEvent(ex.Message, ex.ErrCode);
            }
        }

        public void CMPopAddFetchAttachmentID(Attachment mailAttachment, bool bPreview)
        {
            if (_attDownloadList == null)
                _attDownloadList = new List<CMPopAttDownloadInfo>();

            CMPopAttDownloadInfo attInfo = new CMPopAttDownloadInfo();
            if (attInfo != null)
            {
                attInfo.attachment = mailAttachment;
                attInfo.bPreview = bPreview;
                _attDownloadList.Add(attInfo);
            }
        }

        public void CMPopAddFetchAttachments(List<Attachment> attachmentList, bool bPreview)
        {
            if (_attDownloadList == null)
                _attDownloadList = new List<CMPopAttDownloadInfo>();
            if ((attachmentList == null) || (attachmentList.Count == 0))
                return;
            foreach (Attachment attachment in attachmentList)
            {
                CMPopAttDownloadInfo attInfo = new CMPopAttDownloadInfo();
                if (attInfo != null)
                {
                    attInfo.attachment = attachment;
                    attInfo.bPreview = bPreview;
                    _attDownloadList.Add(attInfo);
                }
            }
        }

        public void StopCMPopRecv()
        {
            if (_nPopState != CMPopState.CMPOP_Quit)
                return;

            _nPopState = CMPopState.CMPOP_Init;
            _sockClient.disConnectToSever();

            _cmPopCommand = null;
        }

        void CMPopChangeState(int nState)
        {
            _nPopState = (CMPopState)nState;

            switch (_nPopState)
            {
                case CMPopState.CMPOP_Init: ;
                    break;

                case CMPopState.CMPOP_Login:
                    _cmPopCommand = null;
                    {
                        _cmPopCommand = new CMPopLogin(_sockClient);
                        _cmPopCommand.CMPopSmtpStateChanged += new CMPopStateEventHandler(CMPopChangeState);
                        _cmPopCommand.TransportEvent += this.TransportEvent;
                    }
                    _cmPopCommand.ReceiveData();
                    break;
                case CMPopState.CMPOP_List:
                    createTaskCommand(_nCMPopTaskType);
                    break;

                case CMPopState.CMPOP_ListEnd:
                    {
                        if (_nCMPopTaskType == CMPopTaskType.CMPopRecvMailTaskType)//receive mail
                        {
                            int nMailCount = ((CMPopList)_cmPopCommand).getMailUidlList().Count;
                            List<string> nMailUidlList = ((CMPopList)_cmPopCommand).getMailUidlList();
                            _cmPopCommand = null;

                            string dumpInfo = String.Format("CMPop:CMPopChangeState mailcount = " + nMailCount.ToString() + "\r\n");
                            DefaultLogger.Log.LogDebug(dumpInfo);
                            //
                            if (nMailCount > 0)
                            {
                                _cmPopCommand = new CMPopRecv(_sockClient);
                                _cmPopCommand.CMPopSmtpStateChanged += new CMPopStateEventHandler(CMPopChangeState);
                                _cmPopCommand.TransportEvent += this.TransportEvent;
                                _nPopState = CMPopState.CMPOP_Recv;
                                ((CMPopRecv)_cmPopCommand).getMail(nMailUidlList);
                            }
                            else
                            {
                                //send notify to UI 
                                System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                                {
                                    this.CMPopCallNotifyInterface(CMPopState.CMPOP_Quit);
                                });
                                _cmPopCommand = new CMPopBase(_sockClient);
                                _cmPopCommand.TransportEvent += this.TransportEvent;
                                _nPopState = CMPopState.CMPOP_Quit;
                                _cmPopCommand.SendData("QUIT\r\n");
                            }
                        }
                    }
                    break;
                case CMPopState.CMPOP_Recv:
                    break;

                case CMPopState.CMPOP_RecvedOneMail:
                    {
                        //send notify to UI 
                        uint mailId = ((CMPopRecv)_cmPopCommand).GetNewMailId();
                        System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            this.CMPopCallNotifyInterface(CMPopState.CMPOP_RecvedOneMail, mailId);
                            //MediaUtils.Vibrate(500);  // lappi 2012/4/25 vibration is handled by hint popup
                        });
                        //DefaultLogger.Log.LogDebug("RecvedOneMail and send notify to UI" + "\r\n");
                    }
                    break;

                case CMPopState.CMPOP_RecvedOneAttachment:
                    {
                        CMPopAttDownloadInfo attInfo = GetAttachmentInfo();
                        PopupAttachmentInfo();
                        //send notify to UI 
                        System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            this.CMPopCallNotifyInterface(CMPopState.CMPOP_RecvedOneAttachment, attInfo);
                        });

                        // DefaultLogger.Log.LogDebug("RecvedOneAttachment and send notify to UI" + "\r\n");
                    }
                    break;
                case CMPopState.CMPOP_RecvedOneAttachmentConvertList:
                    {
                        CMPopAttDownloadInfo attInfo = GetAttachmentInfo();
                        PopupAttachmentInfo();

                        //send notify to UI 
                        System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            this.CMPopCallNotifyInterface(CMPopState.CMPOP_RecvedOneAttachmentConvertList, attInfo);
                        });
                    }
                    break;

                case CMPopState.CMPOP_Quit:
                    System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
                        this.CMPopCallNotifyInterface(CMPopState.CMPOP_Quit);
                    });
                    _cmPopCommand = null;
                    _cmPopCommand = new CMPopBase(_sockClient);
                    _cmPopCommand.TransportEvent += this.TransportEvent;
                    _cmPopCommand.SendData("QUIT\r\n");
                    // DefaultLogger.Log.LogDebug("QUIT\r\n");
                    break;

                default:
                    break;
            }
        }

        void createTaskCommand(CMPopTaskType taskType)
        {
            _cmPopCommand = null;
            switch (taskType)
            {
                case CMPopTaskType.CMPopRecvMailTaskType:
                    {
                        _cmPopCommand = new CMPopList(_sockClient);
                        _cmPopCommand.CMPopSmtpStateChanged += new CMPopStateEventHandler(CMPopChangeState);
                        _cmPopCommand.TransportEvent += this.TransportEvent;
                        ((CMPopList)_cmPopCommand).listMail();
                    }
                    break;
                case CMPopTaskType.CMPopRecvAttachmentTaskType:
                    {
                        //download attachment file
                        _nPopState = CMPopState.CMPOP_FetchAttachement;
                        _cmPopCommand = new CMPopFetchAttachment(_sockClient);
                        _cmPopCommand.CMPopSmtpStateChanged += new CMPopStateEventHandler(CMPopChangeState);
                        _cmPopCommand.TransportEvent += this.TransportEvent;
                        if (this.AttachmentDownloadProcessEvent != null)
                            _cmPopCommand.AttachmentDownloadProcessEvent += this.AttachmentDownloadProcessEvent;
                        ((CMPopFetchAttachment)_cmPopCommand).GetAttDownloadInfo += new CallBackGetAttDownloadInfo(GetAttachmentInfo);
                        if (!((CMPopFetchAttachment)_cmPopCommand).GetAttachmentData())
                        {
                            callErrorTransportEvent("无法下载附件", 200);
                        }
                    }
                    break;
                case CMPopTaskType.CMPopEMSTaskType:
                    {
                        if (popEMS != null)
                        {
                            _cmPopCommand = new CMPopEMS(_sockClient);
                            ((CMPopEMS)_cmPopCommand).emsNotify = popEMS.ems;
                            _cmPopCommand.CMPopSmtpStateChanged += new CMPopStateEventHandler(CMPopChangeState);
                            _cmPopCommand.TransportEvent += this.TransportEvent;
                            ((CMPopEMS)_cmPopCommand).excuteEmsCommand(popEMS);
                        }
                    }
                    break;
                default:
                    break;
            }
        }


        void CMPopCallNotifyInterface(CMPopState popState, object s = null)
        {
            try
            {
                lock (lockObject)
                {
                    if (popNet != null)
                    {
                        switch (popState)
                        {
                            case CMPopState.CMPOP_RecvedOneMail:
                                {
                                    uint mailId = (uint)s;
                                    popNet.ReceivedMailNotify(mailId);
                                }
                                break;
                            case CMPopState.CMPOP_RecvedOneAttachment:
                                {
                                    if (s != null)
                                    {
                                        CMPopAttDownloadInfo attInfo = s as CMPopAttDownloadInfo;
                                        popNet.ReceiveAttchmentNotify(attInfo.attachment.attachmentId);
                                    }
                                }
                                break;
                            case CMPopState.CMPOP_RecvedOneAttachmentConvertList:
                                {
                                    if (s != null)
                                    {
                                        CMPopAttDownloadInfo attInfo = s as CMPopAttDownloadInfo;
                                        popNet.ReceiveAttchmentConvertListNotify(attInfo.attachment.attachmentId);
                                    }
                                }
                                break;
                            case CMPopState.CMPOP_Quit:
                                popNet.ReceiveComplete();
                                break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                DefaultLogger.Log.LogDebug("CMPopCallNotifyInterface Exception" + e.ToString());
            }
        }

        public void callErrorTransportEvent(string strErr, int errCode)
        {
            try
            {
                lock (lockObject)
                {
                    if (TransportEvent != null)
                    {
                        TransportEvent(strErr, errCode);
                    }
                }
            }
            catch (Exception e)
            {
                //DefaultLogger.Log.LogDebug("CMPopCallNotifyInterface Exception" + e.ToString());
            }
        }

        void CMPopProcessConnectMessage()
        {
            switch (_nPopState)
            {
                case CMPopState.CMPOP_Init:
                    CMPopChangeState((int)(CMPopState.CMPOP_Login));
                    break;
                default:
                    break;
            }
        }

        void CMPopProcessSendMessage()
        {
            switch (_nPopState)
            {
                case CMPopState.CMPOP_Init:
                    //do nothing
                    break;

                case CMPopState.CMPOP_Login:
                case CMPopState.CMPOP_List:
                case CMPopState.CMPOP_Recv:
                case CMPopState.CMPOP_RecvedOneMail:
                case CMPopState.CMPOP_FetchAttachement:
                case CMPopState.CMPOP_RecvedOneAttachment:
                case CMPopState.CMPOP_RecvedOneAttachmentConvertList:
                case CMPopState.CMPOP_Ems:
                case CMPopState.CMPOP_EmsEnd:
                    if (_cmPopCommand != null)
                        _cmPopCommand.ReceiveData();
                    break;

                case CMPopState.CMPOP_Quit:
                    StopCMPopRecv();
                    break;

                default:
                    break;
            }
        }

        void CMPopProcessReceiveMessage(string recvString)
        {
            switch (_nPopState)
            {
                case CMPopState.CMPOP_Init:
                    //do nothing
                    break;

                case CMPopState.CMPOP_Login:
                case CMPopState.CMPOP_List:
                case CMPopState.CMPOP_Recv:
                case CMPopState.CMPOP_RecvedOneMail:
                case CMPopState.CMPOP_FetchAttachement:
                case CMPopState.CMPOP_RecvedOneAttachment:
                case CMPopState.CMPOP_RecvedOneAttachmentConvertList:
                case CMPopState.CMPOP_Ems:
                case CMPopState.CMPOP_EmsEnd:
                    if (_cmPopCommand != null)
                        _cmPopCommand.ParseData(recvString);
                    break;

                case CMPopState.CMPOP_Quit:
                    break;

                default:
                    break;
            }
        }

        void CMPopCallBack(object sender, ResponseReceivedEventArgs e)
        {
            try
            {
                if (e.nMessageType == (int)SockMessageType.ConnectSucess)
                {
                    CMPopProcessConnectMessage();
                }
                else if (e.nMessageType == (int)SockMessageType.SendSucess)
                {
                    CMPopProcessSendMessage();
                }
                else if (e.nMessageType == (int)SockMessageType.ReceiveSucess)
                {
                    CMPopProcessReceiveMessage(e.response);
                }
                else
                {
                    string strErr = "";
                    switch (e.nMessageType)
                    {
                        case (int)SockMessageType.ConnectFail:
                        case (int)SockMessageType.ReceiveFail:
                        case (int)SockMessageType.SendFail:
                            strErr = "网络连接失败";
                            break;
                        default:
                            break;

                    }
                    callErrorTransportEvent(strErr, e.nMessageType);
                }
            }
            catch (Exception ex)
            {
                //DefaultLogger.Log.LogDebug("CMPopCallBack " + ex.ToString());
            }
        }

        //CMPopAttDownloadInfo GetAttachmentInfo()
        //{
        //    CMPopAttDownloadInfo attInfo = null;

        //    if (_attDownloadList != null && _attDownloadList.Count > 0)
        //    {
        //        attInfo = _attDownloadList[0];
        //    }
        //    return attInfo;
        //}

        private void PopupAttachmentInfo()
        {
            if (_attDownloadList != null && _attDownloadList.Count > 0)
            {
                _attDownloadList.RemoveAt(0);
            }
        }
    }
}
